package com.bite.gateway.Filter;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSON;
import Constants.HttpConstants;
import Constants.JwtConstants;
import Utils.JwtUtil;
import com.bite.common.security.domain.LoginUser;
import com.bite.common.security.enums.UserType;
import domain.MyThreadLocal;
import domain.R;
import enums.ResultCode;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Value("${jwt.secret}")
    private String secret;


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //获取请求路径
        String url = request.getURI().getPath();
        //判断路径中是否存在login
        if (url.contains("login") || url.contains("sendCode") || url.contains("semiLogin")){
            return chain.filter(exchange);
        }
        //再接着获取token
        String token = request.getHeaders().getFirst(JwtConstants.TOKEN);
        //判断token是否为Null或者是空串或者为空
        if (token == null ||token.isBlank() || token.isEmpty()){
            log.error("token为空");
            return getMono(response, "token为空！", ResultCode.FAILED_UNAUTHORIZED);
        }

        Claims claims;
        try{
          claims = JwtUtil.parseJWT(token, secret);
          if (claims == null){
              log.error("claims为空");
              return getMono(response, "claims为空！", ResultCode.FAILED_UNAUTHORIZED);
          }
        }catch (Exception e){
            log.error("token解析失败");
            return getMono(response, "token解析失败！", ResultCode.FAILED_UNAUTHORIZED);
        }

        //获取用户ID和用户信息
        String userId = claims.get(JwtConstants.USER_ID).toString();
        log.info("用户ID为userId:{}",userId);
        String userKey = claims.get(JwtConstants.USER_KEY).toString();
        log.info("用户信息为userKey:{}",userKey);
        Boolean aBoolean = redisTemplate.hasKey(userKey);
        if (Boolean.FALSE.equals(aBoolean)){
            log.error("令牌已过期");
            return getMono(response, "令牌已过期！", ResultCode.FAILED_UNAUTHORIZED);
        }
        String loginUserStr = redisTemplate.opsForValue().get(userKey);
        LoginUser loginUser = JSONUtil.toBean(loginUserStr, LoginUser.class);
        log.info("用户信息为loginUser:{}",loginUser);

        if (url.contains(HttpConstants.SYSTEM_URL_PREFIX) && !loginUser.getIdentity().equals(UserType.ADMIN_TYPE.getIdentity())){
            log.error("用户无权限操作");
            return getMono(response, "用户无权限操作！", ResultCode.FAILED_UNAUTHORIZED);
        }

        if (url.contains(HttpConstants.FRIEND_URL_PREFIX) && !loginUser.getIdentity().equals(UserType.USER_TYPE.getIdentity())){
            log.error("管理员无权限操作");
            return getMono(response, "管理员无权限操作！", ResultCode.FAILED_UNAUTHORIZED);
        }

        //传递用户信息
        ServerWebExchange ex = exchange.mutate()
                .request(b -> b.header("userId", userId))
                .build();
        //放行
        return chain.filter(ex);
    }

    private Mono<Void> getMono(ServerHttpResponse response,String msg,ResultCode resultCode) {
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().add("Content-Type","text/plain;charset=UTF-8");
        R<Object> r = R.failed(msg, resultCode);
        return response.writeWith(Mono.just(response.bufferFactory().wrap(JSON.toJSONString(r).getBytes())));
    }

    @Override
    public int getOrder() {
        return -200;
    }
}
